package com.xli.organ.user.frameuser.service.impl;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheManager;
import com.alicp.jetcache.anno.CacheConsts;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.template.QuickConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xli.dto.component.util.TreeUtil;
import com.xli.organ.user.frameuser.entity.FrameUser;
import com.xli.organ.user.frameuser.entity.UserCache;
import com.xli.organ.user.frameuser.mapper.FrameUserMapper;
import com.xli.organ.user.frameuser.mapper.IUserCacheMapper;
import com.xli.organ.user.frameuser.service.IFrameUserService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Slf4j
@Validated
@Service
public class FrameUserServiceImpl extends ServiceImpl<FrameUserMapper, FrameUser> implements IFrameUserService {

    private final Lock lock = new ReentrantLock();

    @Autowired
    CacheManager cacheManager;

    Cache<Long, List<UserCache>> userCache;

    @PostConstruct
    public void init() {
        lock.lock();
        try {
            QuickConfig qc = QuickConfig.newBuilder("frame_user:list:")
                    .expire(Duration.ofSeconds(CacheConsts.DEFAULT_EXPIRE))
                    .cacheType(CacheType.LOCAL)
                    .syncLocal(true)
                    .build();
            userCache = cacheManager.getOrCreateCache(qc);

            List<FrameUser> frameUserList = this.findList(new QueryWrapper<>());

            List<UserCache> userCacheList = IUserCacheMapper.INSTANCE.toCacheList(frameUserList);

            Map<Long, List<UserCache>> groupList = userCacheList.stream()
                    .collect(Collectors.groupingBy(UserCache::getOu_id));
            groupList.forEach((ouId, userList) -> {
                userList.sort(Comparator.comparing(UserCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                userCache.put(ouId, userList);
            });
        } finally {
            lock.unlock();
        }
    }


    @Override
    public boolean insert(FrameUser frameUser) {
        lock.lock();
        try {
            boolean result = this.save(frameUser);
            if (result) {
                List<UserCache> userCacheList = userCache.get(generateKey(frameUser));
                if (userCacheList == null) {
                    userCacheList = new ArrayList<>();
                }
                userCacheList.add(IUserCacheMapper.INSTANCE.toCacheEntity(frameUser));
                userCacheList.sort(Comparator.comparing(UserCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                userCache.put(generateKey(frameUser), userCacheList);
            }
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean delete(Long id) {
        lock.lock();
        try {
            FrameUser frameUser = this.find(id);
            if (frameUser != null) {
                boolean result = this.removeById(id);
                if (result) {
                    List<UserCache> userCacheList = userCache.get(generateKey(frameUser));
                    if (userCacheList == null) {
                        userCacheList = new ArrayList<>();
                    }
                    userCacheList.removeIf(cache -> cache.getId().equals(frameUser.getId()));
                    userCache.put(generateKey(frameUser), userCacheList);
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean update(FrameUser frameUser) {
        lock.lock();
        try {
            FrameUser user = this.find(frameUser.getId());
            if (user != null) {
                boolean result = this.updateById(frameUser);
                if (result) {
                    List<UserCache> userCacheList = userCache.get(generateKey(user));
                    if (userCacheList == null) {
                        userCacheList = new ArrayList<>();
                    }
                    userCacheList.removeIf(cache -> cache.getId().equals(user.getId()));
                    if (user.getOu_id().equals(frameUser.getOu_id())) {
                        userCacheList.add(IUserCacheMapper.INSTANCE.toCacheEntity(frameUser));
                        userCacheList.sort(Comparator.comparing(UserCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                        userCache.put(generateKey(user), userCacheList);
                    } else {
                        userCache.put(generateKey(user), userCacheList);
                        userCacheList = userCache.get(generateKey(frameUser));
                        if (userCacheList == null) {
                            userCacheList = new ArrayList<>();
                        }
                        userCacheList.add(IUserCacheMapper.INSTANCE.toCacheEntity(frameUser));
                        userCacheList.sort(Comparator.comparing(UserCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                        userCache.put(generateKey(frameUser), userCacheList);
                    }
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public FrameUser find(Long id) {
        return this.getById(id);
    }

    @Override
    public long findCount(QueryWrapper<FrameUser> qw) {
        return this.count(qw);
    }

    @Override
    public List<FrameUser> findList(QueryWrapper<FrameUser> qw) {
        return this.list(qw);
    }

    @Override
    public Page<FrameUser> findList(QueryWrapper<FrameUser> qw, long current, long size) {
        return this.page(new Page<>(current, size), qw);
    }

    @Override
    public FrameUser findUserByLoginId(String loginId) {
        QueryWrapper<FrameUser> qw = new QueryWrapper<>();
        qw.lambda().eq(FrameUser::getLogin_id, loginId);
        return this.getOne(qw);
    }

    @Override
    public List<FrameUser> findAllUserList() {
        return this.findList(new QueryWrapper<>());
    }

    @Override
    public List<FrameUser> findUserListByOu(Long ouId) {
        List<UserCache> userCacheList = userCache.get(ouId);
        if (userCacheList == null) {
            userCacheList = new ArrayList<>();
        }
        return IUserCacheMapper.INSTANCE.toEntityList(userCacheList, this::find);
    }

    private Long generateKey(FrameUser frameUser) {
        if (frameUser != null && frameUser.getOu_id() != null) {
            return frameUser.getOu_id();
        }
        return TreeUtil.defaultPid;
    }
}
